package de.cbf.cam.dsa.model;

import java.util.List;

import org.apache.log4j.Logger;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;

import de.cbf.cam.dsa.model.base.TalentTmpl;
import de.cbf.cam.dsa.model.entities.ArmorPart;
import de.cbf.cam.dsa.model.entities.OneNPC;
import de.cbf.cam.dsa.model.entities.SF;
import de.cbf.cam.dsa.model.entities.items.Item;
import de.cbf.cam.dsa.model.entities.maneuvers.ManeuverDesc;
import de.cbf.cam.dsa.model.entities.maneuvers.OneManeuver;
import de.cbf.cam.dsa.model.entities.weapon.OneWeapon;
import de.cbf.cam.dsa.model.interfaces.IDataProviderArmor;
import de.cbf.cam.dsa.model.interfaces.IDataProviderItem;
import de.cbf.cam.dsa.model.interfaces.IDataProviderManeuver;
import de.cbf.cam.dsa.model.interfaces.IDataProviderSF;
import de.cbf.cam.dsa.model.interfaces.IDataProviderTalents;
import de.cbf.cam.dsa.model.interfaces.IDataProviderWeapons;
import de.cbf.cam.dsa.model.preferences.PreferenceConstants;
import de.cbf.cam.dsa.model.test.TestDataProvider;

/**
 * The activator class controls the plug-in life cycle
 */
public class Activator extends AbstractUIPlugin {

	/**
	 * Extension point IDs
	 */
	private static final String DataProviderARMOR_ID    = "de.cbf.cam.dsa.model.armorProvider";
	private static final String DataProviderITEM_ID     = "de.cbf.cam.dsa.model.itemProvider";
	private static final String DataProviderMANEUVER_ID = "de.cbf.cam.dsa.model.maneuverProvider";
	private static final String DataProviderSF_ID 		= "de.cbf.cam.dsa.model.sfProvider";
	private static final String DataProviderTALENT_ID	= "de.cbf.cam.dsa.model.talentProvider";
	private static final String DataProviderWEAPON_ID 	= "de.cbf.cam.dsa.model.weaponProvider";

	// The plug-in ID
	public static final String PLUGIN_ID = "de.cbf.cam.dsa.model";

	// The shared instance
	private static Activator plugin;

	public static Logger logger = Logger.getLogger(PLUGIN_ID);
	/**
	 * The constructor
	 */
	public Activator() {
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext)
	 */
	public void start(BundleContext context) throws Exception {
		super.start(context);
		plugin = this;
		onStartUp();
	}

	protected void onStartUp() {
		if(getPreferenceStore().getBoolean(PreferenceConstants.P_LoadFromPlugIns)){
			//if we should load new data from plug-Ins we will
			aquirePlugInProvidedData();
		}

		//for debugging purposes use testdata to init
		List<OneNPC> possibleCharacters = TestDataProvider.providePossibleCharacters();
		Model.getInstance().setPossibleCharacters(possibleCharacters);
		Model.getInstance().setGroupCharacters(possibleCharacters);
	}
	private void aquirePlugInProvidedData() {
		findProvidedArmors();
		findProvidedItems();
		findProvidedManeuvers();
		findProvidedSFs();
		findProvidedTalents();
		findProvidedWeapons();
	}

	private void findProvidedArmors() {
		//evaluating of extension point(Importer) registered extensions
		try {
			IConfigurationElement[] config = Platform.getExtensionRegistry()
					.getConfigurationElementsFor(DataProviderARMOR_ID);
			for (IConfigurationElement configurationElement : config) {
				final Object o = configurationElement.createExecutableExtension("class");
				if (o instanceof IDataProviderArmor) {
					//get attributes
					final IDataProviderArmor provider =(IDataProviderArmor) o;
					final boolean addToDB = configurationElement.getAttribute("addToDB").equals("true");

					//for running of a method in the extension class
					ISafeRunnable runnable = new ISafeRunnable() {
						@Override
						public void handleException(Throwable exception) {
							logger.error("Exception in importer adding: "+exception.getLocalizedMessage());
						}
						@Override
						public void run() throws Exception {
							List<ArmorPart> parts = provider.provideArmor();
							logger.debug("adding "+parts.size()+" armorParts from: "+provider.getName());
							for(int i = 0;i<parts.size();i++){
								ArmorPart armorPart = parts.get(i);
										//logging hint
										StringBuffer buffer = new StringBuffer();
										buffer.append("Adding ArmorPart: ");
										buffer.append(armorPart);
										buffer.append(" to baseModel ");
										if(addToDB){
											buffer.append("(persistent)");
										}
										logger.debug(buffer.toString());
								//register SF
								ModelBase.getInstance().addArmorPart(armorPart,addToDB);
							}
						}
					};
					SafeRunner.run(runnable);
				}
			}
		} catch (Exception ex) {
			logger.error(ex.getMessage());
		}

	}

	private void findProvidedItems() {
		//evaluating of extension point(Importer) registered extensions
		try {
			IConfigurationElement[] config = Platform.getExtensionRegistry()
					.getConfigurationElementsFor(DataProviderITEM_ID);
			for (IConfigurationElement configurationElement : config) {
				final Object o = configurationElement.createExecutableExtension("class");
				if (o instanceof IDataProviderItem) {
					//get attributes
					final IDataProviderItem provider =(IDataProviderItem) o;
					final boolean addToDB = configurationElement.getAttribute("addToDB").equals("true");

					//for running of a method in the extension class
					ISafeRunnable runnable = new ISafeRunnable() {
						@Override
						public void handleException(Throwable exception) {
							logger.error("Exception in importer adding: "+exception.getLocalizedMessage());
						}//
						@Override
						public void run() throws Exception {
							List<Item> items = provider.provideItems();
							logger.debug("adding "+items.size()+" items from: "+provider.getName());
							for(int i = 0;i<items.size();i++){
								Item item = items.get(i);
										//logging hint
										StringBuffer buffer = new StringBuffer();
										buffer.append("Adding item: ");
										buffer.append(item);
										buffer.append(" to baseModel ");
										if(addToDB){
											buffer.append("(persistent)");
										}
										logger.debug(buffer.toString());
								//register SF
								ModelBase.getInstance().addItem(item,addToDB);
							}
						}
					};
					SafeRunner.run(runnable);
				}
			}
		} catch (Exception ex) {
			logger.error(ex.getMessage());
		}

	}

	private void findProvidedManeuvers() {
		//evaluating of extension point(Importer) registered extensions
		try {
			IConfigurationElement[] config = Platform.getExtensionRegistry()
					.getConfigurationElementsFor(DataProviderMANEUVER_ID);
			for (IConfigurationElement configurationElement : config) {
				final Object o = configurationElement.createExecutableExtension("class");
				if (o instanceof IDataProviderManeuver) {
					//get attributes
					final IDataProviderManeuver provider =(IDataProviderManeuver) o;
					final boolean addToDB = configurationElement.getAttribute("addToDB").equals("true");

					//for running of a method in the extension class
					ISafeRunnable runnable = new ISafeRunnable() {
						@Override
						public void handleException(Throwable exception) {
							logger.error("Exception in importer adding: "+exception.getLocalizedMessage());
						}//
						@Override
						public void run() throws Exception {
							List<OneManeuver> maneuvers = provider.provideManeuvers();
							logger.debug("adding "+maneuvers.size()+" maneuvers from: "+provider.getName());
							for(int i = 0;i<maneuvers.size();i++){
								OneManeuver maneuver = maneuvers.get(i);
										//logging hint
										StringBuffer buffer = new StringBuffer();
										buffer.append("Adding maneuver: ");
										buffer.append(maneuver);
										buffer.append(" to maneuvers ");
										if(addToDB){
											buffer.append("(persistent)");
										}
										logger.debug(buffer.toString());
								//register maneuver
								ModelBase.getInstance().registerManeuver(maneuver,addToDB);
							}

							List<ManeuverDesc> maneuverDescs = provider.provideManeuverDescs();
							logger.debug("adding "+maneuverDescs.size()+" maneuverDescriptions from: "+provider.getName());
							for(int i = 0;i<maneuverDescs.size();i++){
								ManeuverDesc maneuver = maneuverDescs.get(i);
										//logging hint
										StringBuffer buffer = new StringBuffer();
										buffer.append("Adding maneuverDesc: ");
										buffer.append(maneuver);
										buffer.append(" to maneuverDescs ");
										if(addToDB){
											buffer.append("(persistent)");
										}
										logger.debug(buffer.toString());
								//register maneuverDesc
								ModelBase.getInstance().registerManeuverDesc(maneuver, addToDB);
							}
						}
					};
					SafeRunner.run(runnable);
				}
			}
		} catch (Exception ex) {
			logger.error(ex.getMessage());
		}
	}


	private void findProvidedSFs() {
		//evaluating of extension point(Importer) registered extensions
		try {
			IConfigurationElement[] config = Platform.getExtensionRegistry()
					.getConfigurationElementsFor(DataProviderSF_ID);
			for (IConfigurationElement configurationElement : config) {
				final Object o = configurationElement.createExecutableExtension("class");
				if (o instanceof IDataProviderSF) {
					//get attributes
					final IDataProviderSF provider =(IDataProviderSF) o;
					final boolean addToDB = configurationElement.getAttribute("addToDB").equals("true");

					//for running of a method in the extension class
					ISafeRunnable runnable = new ISafeRunnable() {
						@Override
						public void handleException(Throwable exception) {
							logger.error("Exception in importer adding: "+exception.getLocalizedMessage());
						}//
						@Override
						public void run() throws Exception {
							List<SF> sfs = provider.provideSFs();
							logger.debug("adding "+sfs.size()+" SFs from: "+provider.getName());
							for(int i = 0;i<sfs.size();i++){
								SF sf = sfs.get(i);
										//logging hint
										StringBuffer buffer = new StringBuffer();
										buffer.append("Adding SF: ");
										buffer.append(sf);
										buffer.append(" to baseModel ");
										if(addToDB){
											buffer.append("(persistent)");
										}
										logger.debug(buffer.toString());
								//register SF
								ModelBase.getInstance().registerSF(sf,addToDB);
							}
						}
					};
					SafeRunner.run(runnable);
				}
			}
		} catch (Exception ex) {
			logger.error(ex.getMessage());
		}
	}

	private void findProvidedTalents() {
		//evaluating of extension point(Importer) registered extensions
		try {
			IConfigurationElement[] config = Platform.getExtensionRegistry()
					.getConfigurationElementsFor(DataProviderTALENT_ID);
			for (IConfigurationElement configurationElement : config) {
				final Object o = configurationElement.createExecutableExtension("class");
				if (o instanceof IDataProviderTalents) {
					//get attributes
					final IDataProviderTalents provider =(IDataProviderTalents) o;
					final boolean addToDB = configurationElement.getAttribute("addToDB").equals("true");

					//for running of a method in the extension class
					ISafeRunnable runnable = new ISafeRunnable() {
						@Override
						public void handleException(Throwable exception) {
							logger.error("Exception in importer adding: "+exception.getLocalizedMessage());
						}//
						@Override
						public void run() throws Exception {
							List<TalentTmpl> talents = provider.providerTalentTemplates();
							logger.debug("adding "+talents.size()+" talents from: "+provider.getName());
							for(int i = 0;i<talents.size();i++){
								TalentTmpl talent = talents.get(i);
										//logging hint
										StringBuffer buffer = new StringBuffer();
										buffer.append("Adding talentTemplate: ");
										buffer.append(talent);
										buffer.append(" to baseModel ");
										if(addToDB){
											buffer.append("(persistent)");
										}
										logger.debug(buffer.toString());
								//register SF
								ModelBase.getInstance().registerTalentTemplate(talent,addToDB);
							}
						}
					};
					SafeRunner.run(runnable);
				}
			}
		} catch (Exception ex) {
			logger.error(ex.getMessage());
		}

	}
	private void findProvidedWeapons() {
		//evaluating of extension point(Importer) registered extensions
		try {
			IConfigurationElement[] config = Platform.getExtensionRegistry()
					.getConfigurationElementsFor(DataProviderWEAPON_ID);
			for (IConfigurationElement configurationElement : config) {
				final Object o = configurationElement.createExecutableExtension("class");
				if (o instanceof IDataProviderWeapons) {
					//get attributes
					final IDataProviderWeapons provider =(IDataProviderWeapons) o;
					final boolean addToDB = configurationElement.getAttribute("addToDB").equals("true");

					//for running of a method in the extension class
					ISafeRunnable runnable = new ISafeRunnable() {
						@Override
						public void handleException(Throwable exception) {
							logger.error("Exception in importer adding: "+exception.getLocalizedMessage());
						}//
						@Override
						public void run() throws Exception {
							List<OneWeapon> weapons = provider.provideWeapons();
							logger.debug("adding "+weapons.size()+" weapons from: "+provider.getName());
							for(int i = 0;i<weapons.size();i++){
								OneWeapon weapon = weapons.get(i);
										//logging hint
										StringBuffer buffer = new StringBuffer();
										buffer.append("Adding weapon: ");
										buffer.append(weapon.getWeaponType());
										buffer.append(" to baseWeapons ");
										if(addToDB){
											buffer.append("(persistent)");
										}
										logger.debug(buffer.toString());
								ModelBase.getInstance().addVirginWeapon(weapon,addToDB);
							}
						}
					};
					SafeRunner.run(runnable);
				}
			}
		} catch (Exception ex) {
			logger.error(ex.getMessage());
		}
	}



	/*
	 * (non-Javadoc)
	 * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext)
	 */
	public void stop(BundleContext context) throws Exception {
		plugin = null;
		super.stop(context);
	}

	/**
	 * Returns the shared instance
	 *
	 * @return the shared instance
	 */
	public static Activator getDefault() {
		return plugin;
	}

	/**
	 * @return the logger
	 */
	public static Logger getLogger() {
		return Logger.getLogger(PLUGIN_ID);
	}
}
